package com.lipengqing.common.utils;

import com.lipengqing.common.utils.spring.SpringUtils;
import org.apache.commons.codec.binary.Hex;
import org.springframework.core.env.Environment;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class CryptoAESUtils {

    /**
     * AES 对称加密
     * CBC 有向量
     * PKCS5Padding 填充模式
     */
    private static final String ALG_AES_CBC_PKCS5 = "AES/CBC/PKCS5Padding";

    private static final String ALGORITHM = "AES";

    private static final Charset UTF8 = StandardCharsets.UTF_8;

    private static String aesKey = SpringUtils.getBean(Environment.class).getProperty("crypto.aesKey"); // 十六位十六进制数作为密钥 // 指定好的秘钥，非Base64和16进制

    private static String aesIv = SpringUtils.getBean(Environment.class).getProperty("crypto.aesIv");  // 十六位十六进制数作为密钥偏移量 // 偏移量

    private static SecretKeySpec skeySpec;

    private static IvParameterSpec iv;

    /**
     * 解密方法
     * @param cipherStr Hex编码的加密字符串
     * @return 解密后的字符串(UTF8编码)
     * @throws Exception 异常
     */
    public static String decrypt(String cipherStr){
        byte[] original = null;
        try {
            // step 1 获得一个密码器
            Cipher cipher = Cipher.getInstance(ALG_AES_CBC_PKCS5);
            // step 2 初始化密码器，指定是加密还是解密(Cipher.DECRYPT_MODE 解密; Cipher.ENCRYPT_MODE 加密)
            // 加密时使用的盐来够造秘钥对象
            skeySpec = new SecretKeySpec(aesKey.getBytes(),ALGORITHM);
            // 加密时使用的向量，16位字符串
            iv = new IvParameterSpec(aesIv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
            byte[] encrypted1 = Hex.decodeHex(cipherStr);
            // 解密后的报文数组
            original = cipher.doFinal(encrypted1);
            // 输出utf8编码的字符串，输出字符串需要指定编码格式
        }catch (Exception e){
            e.printStackTrace();
        }
        return new String(original, UTF8);
    }

    /**
     * 加密
     * @param plainText 明文
     * @return Base64编码的密文
     * @throws Exception  加密异常
     */
    public static String encrypt(String plainText){
        byte [] encryptText = null;
        try {
            Cipher cipher = Cipher.getInstance(ALG_AES_CBC_PKCS5);
            skeySpec = new SecretKeySpec(aesKey.getBytes(),ALGORITHM);
            iv = new IvParameterSpec(aesIv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
            // 这里的编码格式需要与解密编码一致
            encryptText = cipher.doFinal(plainText.getBytes(UTF8));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Hex.encodeHexString(encryptText);
    }

    public static void main(String[] args) {
        String plainText = "a123456"; //ebd1f17742e2db016d78cce88a6a78ac
        String cipherStr;
        System.out.println("加解密前报文:[ " + plainText + " ]");
        cipherStr = encrypt(plainText);
        System.out.println("AES加密后报文:[ " + cipherStr + "]");
        System.out.println("对加密后报文解密后的明文:[ " + decrypt(cipherStr) + " ]");
    }
}
